package com.example.onlineanswer.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.onlineanswer.common.exception.ApiException;
import com.example.onlineanswer.common.util.EmailUtil;
import com.example.onlineanswer.common.util.JwtUtil;
import com.example.onlineanswer.mapper.SysRoleMapper;
import com.example.onlineanswer.mapper.SysUserMapper;
import com.example.onlineanswer.mapper.SysUserRoleMapper;
import com.example.onlineanswer.model.dto.*;
import com.example.onlineanswer.model.entity.SysRole;
import com.example.onlineanswer.model.entity.SysUser;
import com.example.onlineanswer.model.entity.SysUserRole;
import com.example.onlineanswer.model.vo.UserInfoVO;
import com.example.onlineanswer.model.vo.UserListVO;
import com.example.onlineanswer.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final SysUserMapper userMapper;
    private final SysRoleMapper roleMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final EmailUtil emailUtil;
    private final StringRedisTemplate redisTemplate;
    private final JwtUtil jwtUtil;
    
    private static final String EMAIL_CODE_PREFIX = "email:code:";
    private static final int CODE_EXPIRE_MINUTES = 5;
    private static final String[] ALLOWED_ROLES = {"INITIATOR", "CONTESTANT"};
    private static final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(RegisterDTO registerDTO) {
        // 1. 验证角色
        if (!Arrays.asList(ALLOWED_ROLES).contains(registerDTO.getRoleCode())) {
            throw new ApiException("不支持的角色类型");
        }
        // TODO: 2025/4/27 展示不使用验证码
//        // 2. 验证验证码
//        if (!verifyEmailCode(registerDTO.getEmail(), registerDTO.getVerifyCode())) {
//            throw new ApiException("验证码不正确或已过期");
//        }
        
        // 3. 验证用户名是否已存在
        if (checkUsernameExists(registerDTO.getUsername())) {
            throw new ApiException("用户名已存在");
        }
        
        // 4. 验证邮箱是否已存在
        if (checkEmailExists(registerDTO.getEmail())) {
            throw new ApiException("邮箱已存在");
        }
        
        // 5. 获取角色信息
        SysRole role = roleMapper.getByRoleCode(registerDTO.getRoleCode());
        if (role == null) {
            throw new ApiException("角色不存在");
        }
        
        // 6. 创建用户
        SysUser user = new SysUser();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setNickname(registerDTO.getNickname());
        user.setEmail(registerDTO.getEmail());
        user.setStatus(1); // 默认启用
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        
        // 7. 保存用户
        int userResult = userMapper.insert(user);
        if (userResult <= 0) {
            throw new ApiException("用户注册失败");
        }
        
        // 8. 创建用户角色关联
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(role.getId());
        
        // 9. 保存用户角色关联
        int roleResult = userRoleMapper.insert(userRole);
        if (roleResult <= 0) {
            throw new ApiException("用户角色关联失败");
        }
        
        // 10. 注册成功，删除验证码缓存
        redisTemplate.delete(EMAIL_CODE_PREFIX + registerDTO.getEmail());
        
        return true;
    }

    @Override
    public String login(LoginDTO loginDTO) {
        // 1. 根据用户名查询用户
        SysUser user = userMapper.getUserRoleByUsername(loginDTO.getUsername());
        if (user == null) {
            throw new ApiException("用户名或密码错误");
        }
        
        // 2. 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new ApiException("用户名或密码错误");
        }
        
        // 3. 更新登录时间
        SysUser updateUser = new SysUser();
        updateUser.setId(user.getId());
        updateUser.setLastLoginTime(LocalDateTime.now());
        updateUser.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(updateUser);
        
        // 4. 生成JWT令牌
        String token = jwtUtil.generateToken(user.getUsername(), user.getRoleCode(), user.getId());
        
        return token;
    }

    @Override
    public UserInfoVO getUserInfo(Long userId) {
        // 1. 根据ID查询用户
        SysUser user = userMapper.selectById(userId);
        if (user == null) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 查询用户角色信息
        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserRole::getUserId, userId);
        SysUserRole userRole = userRoleMapper.selectOne(wrapper);
        
        SysRole role = null;
        if (userRole != null) {
            role = roleMapper.selectById(userRole.getRoleId());
        }
        
        // 3. 转换为VO
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);
        
        if (role != null) {
            userInfoVO.setRoleCode(role.getRoleCode());
            userInfoVO.setRoleName(role.getRoleName());
        }
        
        return userInfoVO;
    }

    @Override
    public boolean sendEmailVerifyCode(String email) {
        // 1. 校验邮箱是否已被注册
        if (checkEmailExists(email)) {
            throw new ApiException("该邮箱已被注册");
        }
        
        // 2. 生成验证码
        String code = generateVerifyCode();
        
        // 3. 发送验证码邮件
        boolean sendResult = emailUtil.sendVerifyCodeEmail(email, code);
        if (!sendResult) {
            throw new ApiException("验证码发送失败");
        }
        
        // 4. 将验证码保存到Redis中，设置过期时间
        redisTemplate.opsForValue().set(EMAIL_CODE_PREFIX + email, code, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
        
        return true;
    }

    @Override
    public boolean verifyEmailCode(String email, String code) {
        if (!StringUtils.hasText(email) || !StringUtils.hasText(code)) {
            return false;
        }
        
        String cacheCode = redisTemplate.opsForValue().get(EMAIL_CODE_PREFIX + email);
        return code.equals(cacheCode);
    }

    @Override
    public boolean checkUsernameExists(String username) {
        if (!StringUtils.hasText(username)) {
            return false;
        }
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        wrapper.eq(SysUser::getDeleted, false);
        
        return userMapper.selectCount(wrapper) > 0;
    }

    @Override
    public boolean checkEmailExists(String email) {
        if (!StringUtils.hasText(email)) {
            return false;
        }
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getEmail, email);
        wrapper.eq(SysUser::getDeleted, false);
        
        return userMapper.selectCount(wrapper) > 0;
    }

    /**
     * 生成6位随机验证码
     */
    private String generateVerifyCode() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }
    
    @Override
    public IPage<UserListVO> getUserList(UserQueryDTO queryDTO) {
        // 创建分页对象
        Page<SysUser> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        
        // 构建查询条件
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getDeleted, false);
        
        // 添加搜索条件
        if (StringUtils.hasText(queryDTO.getUsername())) {
            wrapper.like(SysUser::getUsername, queryDTO.getUsername());
        }
        if (StringUtils.hasText(queryDTO.getNickname())) {
            wrapper.like(SysUser::getNickname, queryDTO.getNickname());
        }
        if (queryDTO.getStatus() != null) {
            wrapper.eq(SysUser::getStatus, queryDTO.getStatus());
        }
        
        // 按创建时间倒序排序
        wrapper.orderByDesc(SysUser::getCreateTime);
        
        // 执行查询
        IPage<SysUser> userPage = userMapper.selectPage(page, wrapper);
        
        // 转换为VO
        IPage<UserListVO> voPage = userPage.convert(user -> {
            UserListVO vo = new UserListVO();
            BeanUtils.copyProperties(user, vo);
            
            // 查询用户角色
            LambdaQueryWrapper<SysUserRole> urWrapper = new LambdaQueryWrapper<>();
            urWrapper.eq(SysUserRole::getUserId, user.getId());
            SysUserRole userRole = userRoleMapper.selectOne(urWrapper);
            
            if (userRole != null) {
                SysRole role = roleMapper.selectById(userRole.getRoleId());
                if (role != null) {
                    vo.setRoleCode(role.getRoleCode());
                    vo.setRoleName(role.getRoleName());
                }
            }
            
            return vo;
        });
        
        // 如果指定了角色条件，需要进行过滤
        if (StringUtils.hasText(queryDTO.getRoleCode())) {
            List<UserListVO> filteredRecords = voPage.getRecords().stream()
                    .filter(vo -> queryDTO.getRoleCode().equals(vo.getRoleCode()))
                    .collect(Collectors.toList());
            
            voPage.setRecords(filteredRecords);
            voPage.setTotal(filteredRecords.size());
        }
        
        return voPage;
    }
    
    @Override
    public List<String> getAllowedRoles() {
        return Arrays.asList(ALLOWED_ROLES);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addUser(UserAddDTO userAddDTO) {
        // 1. 验证角色
        if (!Arrays.asList(ALLOWED_ROLES).contains(userAddDTO.getRoleCode())) {
            throw new ApiException("不支持的角色类型");
        }
        
        // 2. 验证用户名是否已存在
        if (checkUsernameExists(userAddDTO.getUsername())) {
            throw new ApiException("用户名已存在");
        }
        
        // 3. 验证邮箱是否已存在
        if (checkEmailExists(userAddDTO.getEmail())) {
            throw new ApiException("邮箱已存在");
        }
        
        // 4. 获取角色信息
        SysRole role = roleMapper.getByRoleCode(userAddDTO.getRoleCode());
        if (role == null) {
            throw new ApiException("角色不存在");
        }
        
        // 5. 创建用户
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userAddDTO, user);
        // 密码加密
        user.setPassword(passwordEncoder.encode(userAddDTO.getPassword()));
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        
        // 6. 保存用户
        int userResult = userMapper.insert(user);
        if (userResult <= 0) {
            throw new ApiException("添加用户失败");
        }
        
        // 7. 创建用户角色关联
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(role.getId());
        userRole.setCreateTime(LocalDateTime.now());
        
        // 8. 保存用户角色关联
        int roleResult = userRoleMapper.insert(userRole);
        if (roleResult <= 0) {
            throw new ApiException("用户角色关联失败");
        }
        
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(UserUpdateDTO userUpdateDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userUpdateDTO.getId());
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 如果更新邮箱，需要验证邮箱是否已存在
        if (StringUtils.hasText(userUpdateDTO.getEmail()) 
                && !existUser.getEmail().equals(userUpdateDTO.getEmail())
                && checkEmailExists(userUpdateDTO.getEmail())) {
            throw new ApiException("邮箱已存在");
        }
        
        // 3. 更新用户信息
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userUpdateDTO, user);
        user.setUpdateTime(LocalDateTime.now());
        
        // 4. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("更新用户失败");
        }
        
        return true;
    }
    
    @Override
    public boolean updateUserPassword(UserPasswordDTO userPasswordDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userPasswordDTO.getId());
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 更新密码
        SysUser user = new SysUser();
        user.setId(userPasswordDTO.getId());
        user.setPassword(passwordEncoder.encode(userPasswordDTO.getNewPassword()));
        user.setUpdateTime(LocalDateTime.now());
        
        // 3. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("更新密码失败");
        }
        
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserRole(UserRoleDTO userRoleDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userRoleDTO.getId());
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 验证角色
        if (!Arrays.asList(ALLOWED_ROLES).contains(userRoleDTO.getRoleCode())) {
            throw new ApiException("不支持的角色类型");
        }
        
        // 3. 获取角色信息
        SysRole role = roleMapper.getByRoleCode(userRoleDTO.getRoleCode());
        if (role == null) {
            throw new ApiException("角色不存在");
        }
        
        // 4. 查询用户当前角色
        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserRole::getUserId, userRoleDTO.getId());
        SysUserRole userRole = userRoleMapper.selectOne(wrapper);
        
        // 5. 更新用户角色
        if (userRole == null) {
            // 如果不存在，则创建
            userRole = new SysUserRole();
            userRole.setUserId(userRoleDTO.getId());
            userRole.setRoleId(role.getId());
            userRole.setCreateTime(LocalDateTime.now());
            
            int result = userRoleMapper.insert(userRole);
            if (result <= 0) {
                throw new ApiException("更新用户角色失败");
            }
        } else if (!userRole.getRoleId().equals(role.getId())) {
            // 如果存在但角色不同，则更新
            userRole.setRoleId(role.getId());
            
            int result = userRoleMapper.updateById(userRole);
            if (result <= 0) {
                throw new ApiException("更新用户角色失败");
            }
        }
        
        return true;
    }
    
    @Override
    public boolean updateUserStatus(UserStatusDTO userStatusDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userStatusDTO.getId());
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 检查状态值是否有效
        if (userStatusDTO.getStatus() != 0 && userStatusDTO.getStatus() != 1) {
            throw new ApiException("无效的状态值");
        }
        
        // 3. 更新用户状态
        SysUser user = new SysUser();
        user.setId(userStatusDTO.getId());
        user.setStatus(userStatusDTO.getStatus());
        user.setUpdateTime(LocalDateTime.now());
        
        // 4. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("更新用户状态失败");
        }
        
        return true;
    }
    
    @Override
    public boolean deleteUser(Long userId) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userId);
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 逻辑删除用户
        SysUser user = new SysUser();
        user.setId(userId);
        user.setDeleted(true);
        user.setUpdateTime(LocalDateTime.now());
        
        // 3. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("删除用户失败");
        }
        
        return true;
    }
    
    @Override
    public boolean updateProfile(Long userId, UserProfileUpdateDTO profileUpdateDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userId);
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 如果更新邮箱，需要验证邮箱是否已存在
        if (StringUtils.hasText(profileUpdateDTO.getEmail()) 
                && !existUser.getEmail().equals(profileUpdateDTO.getEmail())
                && checkEmailExists(profileUpdateDTO.getEmail())) {
            throw new ApiException("邮箱已存在");
        }
        
        // 3. 更新用户信息
        SysUser user = new SysUser();
        user.setId(userId);
        user.setNickname(profileUpdateDTO.getNickname());
        user.setEmail(profileUpdateDTO.getEmail());
        user.setPhone(profileUpdateDTO.getPhone());
        user.setGender(profileUpdateDTO.getGender());
        user.setUpdateTime(LocalDateTime.now());
        
        // 4. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("更新个人资料失败");
        }
        
        return true;
    }
    
    @Override
    public boolean updatePassword(Long userId, UserPasswordUpdateDTO passwordUpdateDTO) {
        // 1. 查询用户是否存在
        SysUser existUser = userMapper.selectById(userId);
        if (existUser == null || existUser.getDeleted()) {
            throw new ApiException("用户不存在");
        }
        
        // 2. 验证原密码
        if (!passwordEncoder.matches(passwordUpdateDTO.getOldPassword(), existUser.getPassword())) {
            throw new ApiException("原密码不正确");
        }
        
        // 3. 更新密码
        SysUser user = new SysUser();
        user.setId(userId);
        user.setPassword(passwordEncoder.encode(passwordUpdateDTO.getNewPassword()));
        user.setUpdateTime(LocalDateTime.now());
        
        // 4. 保存更新
        int result = userMapper.updateById(user);
        if (result <= 0) {
            throw new ApiException("修改密码失败");
        }
        
        return true;
    }
} 